//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2005
//
// Move object.
//

# include "StdAfx.h"
# include "MoveObject.h"
# include "UndoRedo.h"
# include "RefreshHoles.h"
# include "Label.h"

class CMoveObjectAction : public CEditAction {
  public:
	CMoveObjectAction (const point_t & _pointShift, rgn_t * _pRgn, size_t _cElementOrOrigin) :
		m_pointShift (_pointShift),
		m_pRgn (_pRgn),
		m_cElementOrOrigin (_cElementOrOrigin),
		m_bWasModified ((_pRgn->dwFlags & rgn_t::fModified) != 0)
	{}

	virtual void GetName (string_t & _str) const;
	virtual cu_t CanUndo () const {return cuYes;}
	virtual bool Do ();
	virtual void Undo ();
	virtual void Redo ();

  private:
	const point_t m_pointShift;
	rgn_t * const m_pRgn;
	const size_t  m_cElementOrOrigin;
	const bool    m_bWasModified;

	void Shift (float _fDx, float _fDy);
};

void CMoveObjectAction::GetName (string_t & _str) const {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);
	if (m_cElementOrOrigin == -1)
		_str.append ("move [");
	else
		_str.append ("move element of [");
	GetHintText (* m_pRgn, _str);
	_str.append ("]");
}

void CMoveObjectAction::Shift (float _fDx, float _fDy) {
	CCritSec::CLock lock (g_cs);

	assert (m_pRgn);

	if (m_pRgn->IsWTR ())
		return;

	if (m_cElementOrOrigin == -1) {
		const size_t cElements = m_pRgn->elements.size ();
		for (size_t cElement = 0; cElement < cElements; ++ cElement) {
			rgn_element_t & element = m_pRgn->elements [cElement];
			if (element.bDeleted)
				continue;

			points_t & points = element.points;
			const size_t cPoints = points.size ();
			for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint) {
				point_t & point = points [cPoint];

				point.x += _fDx;
				point.y += _fDy;
			}
		}

		const size_t cOrigins = m_pRgn->origins.size ();
		for (size_t cOrigin = 0; cOrigin < cOrigins; ++ cOrigin) {
			rgn_origin_t & origin = m_pRgn->origins [cOrigin];
			if (origin.bDeleted)
				continue;

			origin.point.x += _fDx;
			origin.point.y += _fDy;
		}
	} else {
		if (m_pRgn->origins.empty ()) {
			assert (m_cElementOrOrigin < m_pRgn->elements.size ());
			points_t & points = m_pRgn->elements [m_cElementOrOrigin].points;
			const size_t cPoints = points.size ();
			for (size_t cPoint = 0; cPoint < cPoints; ++ cPoint) {
				point_t & point = points [cPoint];

				point.x += _fDx;
				point.y += _fDy;
			}
		} else {
			assert (m_cElementOrOrigin < m_pRgn->origins.size ());
			point_t & point = m_pRgn->origins [m_cElementOrOrigin].point;

			point.x += _fDx;
			point.y += _fDy;
		}
	}

	m_pRgn->RefreshAttributes (g_map, false);
}

bool CMoveObjectAction::Do () {
	Shift (m_pointShift.x, m_pointShift.y);
	m_pRgn->dwFlags |= rgn_t::fModified;
	return true;
}

void CMoveObjectAction::Undo () {
	Shift (- m_pointShift.x, - m_pointShift.y);

	if (! m_bWasModified)
		m_pRgn->dwFlags &= ~rgn_t::fModified;
}

void CMoveObjectAction::Redo () {
	CMoveObjectAction::Do ();
}

///////////////////////////////////////////

void MoveObject (rgn_t * _pRgn, size_t _cElementOrOrigin, const point_t & _pointShift) {
	PerformEditAction (new CMoveObjectAction (_pointShift, _pRgn, _cElementOrOrigin));

	if (_pRgn->IsPolygon () && _cElementOrOrigin != -1)
		RefreshHoles (_pRgn, true);
}
